package com.zzjson.design.proxy.custom;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * <p>****************************************************************************</p>
 * <p><b>Copyright © 2010-2018 rollBall team All Rights Reserved<b></p>
 * <ul style="margin:15px;">
 * <li>Description : 生成代理对象</li>
 * <li>Version     : 1.0.0</li>
 * <li>Creation    : 2018年11月30日</li>
 * <li>@author     : zzy0_0</li>
 * </ul>
 * <p>****************************************************************************</p>
 */
public class MyProxy {
    private static String newLine = "\r\n";

    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler myInvocationHandler)
            throws IllegalArgumentException, ClassNotFoundException {
        //1.生成源代码
        String proxySrc = generateSrc(interfaces[0]);
        //2.把生成的源代码输出到磁盘保存为.java文件
        String filePath = MyProxy.class.getResource("").getPath();
        File f = new File(filePath + "$Proxy0.java");
        FileWriter fw = null;
        try {
            fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.close();
            //3.编译源代码,并且生成.class文件
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);
            //创建编译任务
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();

            //4.把class文件中的内容动态加载到jvm中
            Class proxyClass = loader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
            //5.返回被代理后的对象
            return c.newInstance(myInvocationHandler);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private static String generateSrc(Class<?> interfaces) {
        StringBuilder src = new StringBuilder();
        src.append("package cn.zzjson.design.proxy.custom;" + newLine);
        src.append("import java.lang.reflect.Method;" + newLine);
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + newLine);
        src.append("MyInvocationHandler h;" + newLine);
        src.append("public $Proxy0(MyInvocationHandler h){" + newLine);
        src.append("this.h=h;" + newLine);
        src.append("}" + newLine);

        for (Method m : interfaces.getMethods()) {
            src.append("public " + m.getReturnType() + " " + m.getName() + "() {" + newLine);
            src.append("try{");
            src.append("Method m=" + interfaces.getName() + ".class.getMethod(\"" + m.getName() + "\");");
            src.append("this.h.invoke(this,m,null);");
            src.append("}catch(Throwable t)");
            src.append("{t.printStackTrace();}" + newLine);
            src.append("}" + newLine);

        }
        src.append("}");
        return src.toString();
    }
}